module Control(
input Clk, 
input Reset, 
input [5:0] Op, 
output reg PCWriteCond, 
output reg PCWrite, 
output reg lorD, 
output reg MemRead, 
output reg MemWrite,
output reg MemtoReg, 
output reg IRWrite, 
output reg [1:0] PCSource, 
output reg [1:0] ALUOp, 
output reg [1:0] ALUSrcB, 
output reg ALUSrcA, 
output reg RegWrite, 
output reg RegDst
);

reg [4:0] EstadoActual =0; 
//reg [4:0] Inicio;
reg [4:0] SiguienteEstado=0;

parameter [3:0] S0=0;
parameter [3:0] S1=1;
parameter [3:0] S2=2;
parameter [3:0] S3=3;
parameter [3:0] S4=4;
parameter [3:0] S5=5;
parameter [3:0] S6=6;
parameter [3:0] S7=7;
parameter [3:0] S8=8;
parameter [3:0] S9=9;
parameter [3:0] S10=10;//inmediato
parameter [3:0] S11=11; //inmediato

always@(posedge Clk) begin
 if (Reset)
    EstadoActual <= S0;
 else 
    EstadoActual <= SiguienteEstado;
end

always @(*) begin
		MemRead = 1'b0;  //1
		ALUSrcA = 1'b0;  //2
		lorD= 1'b0;       //3
		IRWrite = 1'b0;   //4
		ALUSrcB = 2'b00;  //5
		ALUOp= 2'b00;     //6
		PCWrite = 1'b0;   //7
		PCSource = 2'b00;   //8
		RegWrite = 1'b0;	
		MemWrite = 1'b0;
		RegDst = 1'b0;
		MemtoReg = 1'b0;
		PCWriteCond = 1'b0;
		SiguienteEstado = EstadoActual;
case(EstadoActual)
S0: begin //fetch
      MemRead = 1'b1;  //1
      ALUSrcA = 1'b0;  //2
      lorD= 1'b0;       //3
      IRWrite = 1'b1;   //4
      ALUSrcB = 2'b01;  //5
      ALUOp= 2'b00;     //6
      PCWrite = 1'b1;   //7
      PCSource = 2'b00;   //8 
      
      RegWrite = 1'b0;    //10
      MemWrite = 1'b0;    //11  
      PCWriteCond = 1'b0;   //12
      MemtoReg = 1'b0;    //13
      RegDst = 1'b0;
      SiguienteEstado = S1;
    end
S1: begin  //decodificacion 
      MemRead=1'b0;
      IRWrite=1'b0;
      ALUSrcA=1'b0;
      ALUSrcB=2'b11;
      PCWrite=1'b0;
      ALUOp= 2'b00;
      //si el op code carga ld o un std
      if(Op==6'h 23 || Op==6'h 2B) begin SiguienteEstado=S2; end
        //if R type instruction
      if(Op==6'h 00) begin SiguienteEstado=S6; end
      //salto si es igual
      if(Op==6'h 04) begin SiguienteEstado=S8; end
      //si es un salto
      if(Op==6'h 02) begin SiguienteEstado=S9; end
      // pal inmediato  
  //    if((Op==6'b001100)|(Op==6'b001101)|(Op==6'b001110)|(Op==6'b001111)) begin SiguienteEstado = S10; end // estado extra
      if((Op==6'h 07)|(Op==6'h 0D)|(Op==6'h 0E )|(Op==6'h 0F)) begin SiguienteEstado = S10; end // estado extra
    end
S2: begin // memory addres computation  
      ALUSrcA = 1'b1;
      ALUSrcB= 2'b10;
      ALUOp = 2'b00;
      //    ld
      if(Op==6'h 23) begin SiguienteEstado=S3; end
      //std
      if(Op==6'h 2B) begin SiguienteEstado=S5; end
    end
    
S3: begin
      MemRead=1'b1;
      lorD = 1'b1;
      SiguienteEstado=S4;
    end
S4: begin
      RegDst = 1'b0;
      RegWrite = 1'b1;
      MemtoReg= 1'b1;
      MemRead=1'b0;
      SiguienteEstado=S0;
    end
S5: begin  //para el sw
      ALUSrcB= 2'b00; //aqui
      MemWrite=1'b1;
      lorD= 1'b1;
      SiguienteEstado=S0; // se acaba
    end
S6: begin // del estado uno cuando es  tipo registro
      ALUSrcA= 1'b1;  //execute
      ALUSrcB= 2'b00;
      ALUOp = 2'b10;
      SiguienteEstado = S7;  
    end
S7: begin 
      RegDst= 1'b1;
      RegWrite = 1'b1;
      MemtoReg = 1'b0;
      SiguienteEstado= S0; // se acaba
    end
S8: begin
      ALUSrcA= 1'b1;
      ALUSrcB= 2'b00;
      ALUOp=2'b01;
      PCWriteCond= 1'b1;
      PCSource = 2'b01;
      SiguienteEstado= S0; // se acaba
    end
S9: begin
      PCWrite= 1'b1;
      PCSource= 2'b10;
      SiguienteEstado= S0; //se acaba
    end
    //estado para los opcode cuando la instruccion en inmediata  
S10: begin
      ALUSrcA= 1'b1;
      ALUSrcB= 2'b10;
      ALUOp = 2'b11;
      SiguienteEstado = S11;
end
S11: begin
      RegDst= 1'b0;
      RegWrite = 1'b1;
      MemtoReg = 1'b0;
      SiguienteEstado = S0;
    end
default:
      SiguienteEstado = S0;  //al fetch estado inicial
  endcase
  end
endmodule
